﻿using System;
using System.Collections.Generic;
using System.IO;

namespace SharedTypes
{
    /// <summary>
    /// Структура, содержащая информацию о проведённой адаптации и ее SR-оценки.
    /// </summary>
    public struct ReportInformationContainer
    {
        /// <summary>
        /// Показывает отношение размеров сжатой выборки с рекомендуемыми
        /// параметрами к новой с найденными параметрами.
        /// </summary>
        public double bestFitness { get; set; }

        /// <summary>
        /// Дата произведения адаптации.
        /// </summary>
        public DateTime LaunchDate { get; set; }

        /// <summary>
        /// Время, затраченное на адаптацию с подобраными параметрами.
        /// </summary>
        public TimeSpan TotalElapsedTime{ get; set; }

        /// <summary>
        /// Форматирование время, затраченное на адаптацию с подобраными параметрами.
        /// </summary>
        public string TotalElapsedTimeFomatted
        {
            get
            {
                return string.Format("{0:00}.{1:00}",
                  this.TotalElapsedTime.Hours * 3600 + this.TotalElapsedTime.Minutes * 60 +
                  this.TotalElapsedTime.Seconds, this.TotalElapsedTime.Milliseconds);
            }
        }

        /// <summary>
        /// Время, затраченное на каждый набор параметров последнего поколения
        /// </summary>
        public TimeSpan[] ElapsedTime { get; set; }

        /// <summary>
        /// Имя адаптируемого алгоритма.
        /// </summary>
        public string AlgorithmName { get; set; }

        /// <summary>
        /// Имя метода адаптации.
        /// </summary>
        public string MethodName { get; set; }

        /// <summary>
        /// Список файлов тестовой выборки.
        /// </summary>
        public FileInfo[] FileNames { get; set; }

        /// <summary>
        /// Лучший набор параметров алгоритма в процессе адаптации.
        /// </summary>
        public IDictionary<int, LinkedParameter> FindedParameters { get; set; }

        /// <summary>
        /// Список наборов параметров на последнем шаге алгоритма в процессе адаптации.
        /// </summary>
        public IDictionary<int, LinkedParameter>[] LastGenParameters { get; set; }

        /// <summary>
        /// Список отношений размера архива при рекомендуемых настройках к полученному при текущих 
        /// настройках на последнем шаге алгоритма в процессе адаптации.
        /// </summary>
        public double[] LastGenFitness { get; set; }

        /// <summary>
        /// Размер архива при сжатии с рекомендуемыми параметрами
        /// </summary>
        public double recommendedResult { get; set; }

         /// <summary>
        /// Размер архива при сжатии с лучшими параметрами
        /// </summary>
        public double bestSize
        { 
            get
            {
                return recommendedResult / bestFitness;
            }
        }

        /// <summary>
        /// Время исполнительного файла при рекомендуемых параметрах
        /// </summary>
        public TimeSpan RecommendedResultTime { get; set; }

        /// <summary>
        /// Форматирование время, затраченное на адаптацию с реккомендуемыми параметрами.
        /// </summary>
        public string RecommendedResultTimeFomatted
        {
            get
            {
                return string.Format("{0:00}.{1:00}",
                  this.RecommendedResultTime.Hours * 3600 + this.RecommendedResultTime.Minutes * 60 +
                  this.RecommendedResultTime.Seconds, this.RecommendedResultTime.Milliseconds);
            }
        }

        /// <summary>
        /// Время затраченное на поиск параметров
        /// </summary>
        public TimeSpan SearchingTime { get; set; }

        /// <summary>
        /// Форматирование время, затраченное на поиск параметров.
        /// </summary>
        public string SearchingTimeFomatted
        {
            get
            {
                return string.Format("{0:00}.{1:00}",
                  this.SearchingTime.Hours * 3600 + this.SearchingTime.Minutes * 60 +
                  this.SearchingTime.Seconds, this.SearchingTime.Milliseconds);
            }
        }

        /// <summary>
        /// Количество экспериментов
        /// </summary>
        public double ExperimentCount { get; set; }

        /// <summary>
        /// Список Sup по времени
        /// </summary>
        public List<double> SupTime { get; set; }

        /// <summary>
        /// Список Sup по сжатию
        /// </summary>
        public List<double> SupCompression { get; set; }

        /// <summary>
        /// Список Reg по времени
        /// </summary>
        public List<double> RegTime { get; set; }

        /// <summary>
        /// Список Reg по сжатию
        /// </summary>
        public List<double> RegCompression { get; set; }

        /// <summary>
        /// Метод глубокого копирования.
        /// </summary>
        /// 
        public void CopyHere(ReportInformationContainer param, bool isCopied)
        {
            this.bestFitness = param.bestFitness;
            this.LaunchDate = param.LaunchDate;
            this.TotalElapsedTime = param.TotalElapsedTime;
			this.ElapsedTime = param.ElapsedTime;
            this.AlgorithmName = param.AlgorithmName;
            this.MethodName = param.MethodName;
            this.FileNames = param.FileNames;
            this.FindedParameters = param.FindedParameters;
            this.LastGenParameters = param.LastGenParameters;
            this.LastGenFitness = param.LastGenFitness;
            this.recommendedResult = param.recommendedResult;
            this.RecommendedResultTime = param.RecommendedResultTime;
            this.ExperimentCount = param.ExperimentCount;
            if (this.SupTime == null)
            {
                this.SupTime = new List<double>();
            }
            if (this.SupCompression == null)
            {
                this.SupCompression = new List<double>();
            }
            if (this.RegTime == null)
            {
                this.RegTime = new List<double>();
            }
            if (this.RegCompression == null)
            {
                this.RegCompression = new List<double>();
            }

            if (!isCopied)
            {
                return;
            }

            if (param.SupTime.Count != 0)
            {
                this.SupTime.AddRange(param.SupTime.ToArray());
            }
            if (param.SupCompression.Count != 0)
            {
                this.SupCompression.AddRange(param.SupCompression.ToArray());
            }
            if (param.RegTime.Count != 0)
            {   
                this.RegTime.AddRange(param.RegTime.ToArray());
            }
            if (param.RegCompression.Count != 0)
            {
                this.RegCompression.AddRange(param.RegCompression.ToArray());
            }
        }

        /// <summary>
        /// Устанавливает мах значения.
        /// </summary>
        public void SetMaxValues()
        {
           this.bestFitness = 1;
           this.ElapsedTime = null;
           this.recommendedResult = double.MaxValue;
           this.TotalElapsedTime = TimeSpan.MaxValue;
        }

        /// <summary>
        /// Очищает все содержащиеся данные.
        /// </summary>
        public void Clear()
        {
            bestFitness = 0;
            TotalElapsedTime = new TimeSpan();
            LaunchDate = new DateTime();
        }

        /// <summary>
        /// Подсчитывает Sup по времени для всех экспериментов
        /// </summary>
        public double CalculateSupTime()
        {
            double result = 0;
            foreach (double sup in this.SupTime)
            {
                result += sup;
            }
            return Math.Round(result / this.SupTime.Count, 4);
        }

        /// <summary>
        /// Подсчитывает Sup по степени исполнительного файла для всех экспериментов
        /// </summary>
        public double CalculateSupCompression()
        {
            double result = 0;
            foreach (double sup in this.SupCompression)
            {
                result += sup;
            }
            return Math.Round(result / this.SupCompression.Count, 4);
        }

        /// <summary>
        /// Подсчитывает Reg по времени для всех экспериментов
        /// </summary>
        public double CalculateRegTime()
        {
            double result = 0;
            foreach (double reg in this.RegTime)
            {
                result += reg;
            }
            return Math.Round(result / this.RegTime.Count, 4);
        }

        /// <summary>
        /// Подсчитывает Reg по степени исполнительного файла для всех экспериментов
        /// </summary>
        public double CalculateRegCompression()
        {
            double result = 0;
            foreach (double reg in this.RegCompression)
            {
                result += reg;
            }
            return Math.Round(result / this.RegCompression.Count, 4);
        }

        /// <summary>
        /// Подсчитывает размер файлов
        /// </summary>
        public double CalculateDirSize()
        {
            double result = 0;
            foreach (FileInfo file in this.FileNames)
            {
                try
                {
                    result += file.Length;
                }
                catch (FileNotFoundException ex)
                {

                }
            }
            return result;
        }
    }
}